package com.mmc.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmc.entity.Role;
import com.mmc.mapper.RoleMapper;
import com.mmc.mapper.RoleMenuMapper;
import com.mmc.mapper.UserRoleMapper;
import com.mmc.service.RoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 角色服务实现类
 *
 * @author kunfe
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMapper roleMapper;
    private final RoleMenuMapper roleMenuMapper;
    private final UserRoleMapper userRoleMapper;

    @Override
    public Page<Role> getRolePage(Page<Role> page, String roleName, String roleCode, Integer status) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<Role>()
                .like(ObjectUtil.isNotEmpty(roleName), Role::getRoleName, roleName)
                .like(ObjectUtil.isNotEmpty(roleCode), Role::getRoleCode, roleCode)
                .eq(ObjectUtil.isNotNull(status), Role::getStatus, status)
                .orderByAsc(Role::getSort)
                .orderByDesc(Role::getCreateTime);
        
        return page(page, wrapper);
    }

    @Override
    public Role getRoleByCode(String roleCode) {
        return getOne(new LambdaQueryWrapper<Role>()
                .eq(Role::getRoleCode, roleCode));
    }

    @Override
    public boolean existsRoleCode(String roleCode, Long excludeId) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<Role>()
                .eq(Role::getRoleCode, roleCode)
                .ne(ObjectUtil.isNotNull(excludeId), Role::getId, excludeId);
        return count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createRole(Role role) {
        // 检查角色编码是否存在
        if (existsRoleCode(role.getRoleCode(), null)) {
            throw new RuntimeException("角色编码已存在");
        }
        
        // 设置默认值
        if (role.getStatus() == null) {
            role.setStatus(1);
        }
        if (role.getSort() == null) {
            role.setSort(0);
        }
        if (role.getDataScope() == null) {
            role.setDataScope(1);
        }
        if (role.getRoleType() == null) {
            role.setRoleType(2);
        }
        
        boolean result = save(role);
        
        // 分配菜单权限
        if (result && CollUtil.isNotEmpty(role.getMenuIds())) {
            assignMenus(role.getId(), role.getMenuIds());
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateRole(Role role) {
        Role existRole = getById(role.getId());
        if (existRole == null) {
            throw new RuntimeException("角色不存在");
        }
        
        // 检查角色编码是否存在
        if (!existRole.getRoleCode().equals(role.getRoleCode()) && existsRoleCode(role.getRoleCode(), role.getId())) {
            throw new RuntimeException("角色编码已存在");
        }
        
        boolean result = updateById(role);
        
        // 更新菜单权限
        if (result && role.getMenuIds() != null) {
            assignMenus(role.getId(), role.getMenuIds());
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRole(Long roleId) {
        // 检查是否有用户使用该角色
        if (hasUsers(roleId)) {
            throw new RuntimeException("该角色下还有用户，无法删除");
        }
        
        // 删除角色菜单关联
        roleMenuMapper.deleteByRoleId(roleId);
        
        return removeById(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteRole(List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return false;
        }
        
        // 检查是否有用户使用这些角色
        for (Long roleId : roleIds) {
            if (hasUsers(roleId)) {
                Role role = getById(roleId);
                throw new RuntimeException("角色【" + role.getRoleName() + "】下还有用户，无法删除");
            }
        }
        
        // 删除角色菜单关联
        roleMenuMapper.batchDeleteByRoleIds(roleIds);
        
        return removeByIds(roleIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(Long roleId, Integer status) {
        Role role = new Role();
        role.setId(roleId);
        role.setStatus(status);
        
        return updateById(role);
    }

    @Override
    public List<Role> getUserRoles(Long userId) {
        return userRoleMapper.selectRolesByUserId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean assignMenus(Long roleId, List<Long> menuIds) {
        // 删除原有菜单权限
        roleMenuMapper.deleteByRoleId(roleId);
        
        // 分配新菜单权限
        if (CollUtil.isNotEmpty(menuIds)) {
            return roleMenuMapper.batchInsert(roleId, menuIds) > 0;
        }
        
        return true;
    }

    @Override
    public List<Long> getRoleMenuIds(Long roleId) {
        return roleMenuMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    public List<Role> getEnabledRoles() {
        return list(new LambdaQueryWrapper<Role>()
                .eq(Role::getStatus, 1)
                .orderByAsc(Role::getSort));
    }

    @Override
    public List<String> getPermissionsByUserId(Long userId) {
        return roleMapper.selectPermissionsByUserId(userId);
    }

    @Override
    public boolean hasPermission(Long userId, String permission) {
        List<String> permissions = getPermissionsByUserId(userId);
        return permissions.contains(permission);
    }

    @Override
    public boolean hasRole(Long userId, String roleCode) {
        List<Role> roles = getUserRoles(userId);
        return roles.stream().anyMatch(role -> role.getRoleCode().equals(roleCode));
    }

    /**
     * 检查角色是否有用户使用
     */
    private boolean hasUsers(Long roleId) {
        List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(roleId);
        return CollUtil.isNotEmpty(userIds);
    }
} 